﻿using System;
using System.Windows;
using System.Windows.Media;

namespace VisualView.Series
{
    /// <summary>
    /// 散点图
    /// </summary>
    /// <typeparam name="TX"></typeparam>
    /// <typeparam name="TY"></typeparam>
    public class PointXYSeries<TX, TY> : BaseXYSeries<TX, TY>
    {
        #region 绘制点形状
        #region 圆形
        public static void DrawEllipsePoint(StreamGeometryContext sc, double x, double y, Size size)
        {
            sc.BeginFigure(new Point(x - size.Width, y), true, true);
            sc.ArcTo(new Point(x + size.Width, y), size, 0, true, SweepDirection.Clockwise, true, true);
            sc.ArcTo(new Point(x - size.Width, y), size, 0, true, SweepDirection.Clockwise, true, true);
        }
        public static Action<StreamGeometryContext, double, double, Size> DrawEllipsePointAction = new Action<StreamGeometryContext, double, double, Size>(DrawEllipsePoint);
        #endregion
        #region 方形
        public static void DrawRectanglePoint(StreamGeometryContext sc, double x, double y, Size size)
        {
            sc.BeginFigure(new Point(x - size.Width, y - size.Height), true, true);
            sc.PolyLineTo(new Point[] { new Point(x - size.Width, y + size.Height), new Point(x + size.Width, y + size.Height), new Point(x + size.Width, y - size.Height) }, true, true);
        }
        public static Action<StreamGeometryContext, double, double, Size> DrawRectanglePointAction = new Action<StreamGeometryContext, double, double, Size>(DrawRectanglePoint);
        #endregion
        #region 三角形
        public static void DrawTranglePoint(StreamGeometryContext sc, double x, double y, Size size)
        {
            sc.BeginFigure(new Point(x - size.Width, y - size.Height), true, true);
            sc.PolyLineTo(new Point[] { new Point(x + size.Width, y - size.Height), new Point(x, y + size.Height) }, true, true);
        }
        public static Action<StreamGeometryContext, double, double, Size> DrawTranglePointAction = new Action<StreamGeometryContext, double, double, Size>(DrawTranglePoint);
        #endregion
        #endregion

        #region 形状绘制属性
        public static Size DefaultPointSize = new Size(8d, 8d);
        /// <summary>
        /// 点大小,半径
        /// </summary>
        public Size PointSize
        {
            get { return (Size)GetValue(PointSizeProperty); }
            set { SetValue(PointSizeProperty, value); }
        }
        public static readonly DependencyProperty PointSizeProperty = DependencyProperty.Register("PointSize", typeof(Size), typeof(PointXYSeries<TX, TY>), new PropertyMetadata(DefaultPointSize, PropertyChangedNeedRedraw));

        /// <summary>
        /// 绘制点形状方法
        /// </summary>
        public Action<StreamGeometryContext, double, double, Size> DrawPointAction
        {
            get { return (Action<StreamGeometryContext, double, double, Size>)GetValue(DrawPointActionProperty); }
            set { SetValue(DrawPointActionProperty, value); }
        }
        public static readonly DependencyProperty DrawPointActionProperty = DependencyProperty.Register("DrawPointAction", typeof(Action<StreamGeometryContext, double, double, Size>), typeof(PointXYSeries<TX, TY>), new PropertyMetadata(DrawEllipsePointAction, PropertyChangedNeedRedraw));
        #endregion

        protected override Geometry CreateGeometry(int count, Func<int, double> getXFunc, Func<int, double> getYFunc)
        {
            Size size = DefaultPointSize;
            Action<StreamGeometryContext, double, double, Size> action = DrawEllipsePointAction;
            this.Dispatcher.Invoke(() =>
            {
                if (DrawPointAction != null) action = DrawPointAction;
                if (PointSize != Size.Empty && PointSize.Width > 0 && PointSize.Height > 0) size = PointSize;
            });
            var geometry = new StreamGeometry();
            using (var sc = geometry.Open()) for (int i = 0; i < count; i++) action(sc, getXFunc(i), getYFunc(i), size);
            return geometry;
        }
    }

    public class PointDoubleXYSeries : PointXYSeries<double, double> { }
    public class PointDoubleXDateTimeYSeries : PointXYSeries<double, DateTime> { }
    public class PointDoubleXTimeSpanYSeries : PointXYSeries<double, TimeSpan> { }

    public class PointDateTimeXYSeries : PointXYSeries<DateTime, DateTime> { }
    public class PointDateTimeXDoubleYSeries : PointXYSeries<DateTime, double> { }
    public class PointDateTimeXTimeSpanYSeries : PointXYSeries<DateTime, TimeSpan> { }

    public class PointTimeSpanXYSeries : PointXYSeries<TimeSpan, TimeSpan> { }
    public class PointTimeSpanXDoubleY : PointXYSeries<TimeSpan, double> { }
    public class PointTimeSpanXDateTimeY : PointXYSeries<TimeSpan, DateTime> { }
}
